package com.weike.bsp.dao

import com.weike.bsp.model.AccessToken
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.data.r2dbc.core.select
import org.springframework.data.relational.core.query.Criteria
import org.springframework.data.relational.core.query.CriteriaDefinition
import org.springframework.data.relational.core.query.Query
import org.springframework.r2dbc.core.DatabaseClient
import org.springframework.r2dbc.core.bind
import org.springframework.stereotype.Repository
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.time.LocalDateTime

@Repository
class AccessTokenRepo(
    private val databaseClient: DatabaseClient,
    private val template: R2dbcEntityTemplate
) {

    fun insert2(accessToken: AccessToken): Mono<Int?> {
        return databaseClient.sql("insert into pub_access_token (access_token, user_id, username, created_at, expired_at, id) values (:access_token, :user_id, :username, :created_at, :expired_at, :id)")
            .bind("access_token", accessToken.token)
            .bind("user_id", accessToken.userId)
            .bind("username", accessToken.username)
            .bind("created_at", LocalDateTime.now())
            .bind("expired_at", LocalDateTime.now().plusDays(7))
            .bind("id", System.currentTimeMillis())
            .fetch()
            .rowsUpdated()
    }

    fun insert(accessToken: AccessToken): Mono<AccessToken?> {
        return template.insert(AccessToken::class.java).using(accessToken)
    }

    /**
     * 根据token 获取，且是可用的token
     */
    fun findByToken(token: String): Mono<AccessToken?> {
        val q = Query.query(Criteria.where("access_token").`is`(token))
        return template.select<AccessToken>().from("pub_access_token")
            .matching(q)
            .one()
    }

    fun findById(id: Long): Mono<AccessToken?> {
        val q = Query.query(Criteria.where("id").`is`(id))
        return template.select<AccessToken>().from("pub_access_token")
            .matching(q)
            .one()
    }

    fun deleteByToken(token: String): Mono<Int> {
        val q = Query.query(Criteria.where("access_token").`is`(token))
        return template.delete(AccessToken::class.java)
            .matching(q)
            .all()
    }

    fun deleteById(id: Long): Mono<Int> {
        val q = Query.query(Criteria.where("id").`is`(id))
        return template.delete(AccessToken::class.java)
            .matching(q)
            .all()
    }

    fun deleteInIds(ids: List<Long>): Mono<Int> {
        val q = Query.query(Criteria.where("id").`in`(ids))
        return template.delete(AccessToken::class.java)
            .matching(q)
            .all()
    }

    fun deleteByUsername(username: String): Mono<Int> {
        val q = Query.query(Criteria.where("username").`is`(username))
        return template.delete(AccessToken::class.java)
            .matching(q)
            .all()
    }

    fun findByUsername(username: String): Mono<AccessToken?> {
        val q = Query.query(Criteria.where("username").`is`(username))
        return template.select<AccessToken>()
            .matching(q)
            .one()
    }

    fun findAll(): Flux<AccessToken> {
//        template.select(Query.query(CriteriaDefinition.empty()), AccessToken::class.java)
        return template.select<AccessToken>().all()
    }
}
